
<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <title>NESASM</title>
    <style>
    html,body{font-size:14px; color:#444;} 
    a {text-decoration: none; color:blue;}
    a:hover{color:red;}
    .main{margin:0 auto; width:960px;}
    .box{border:1px solid #eee;}
    </style>
</head>

<body>

<div class="main">
<p>【主角】
</p><p>主角和背景比起来，你肯定觉得背景会更简单。错！主角才简单得要命。
</p><p>制造主角只需要向SPR-RAM写入一点点内容（主角的x，y坐标，tile编号，等等）。
</p><p>等等，我觉得咱们得先绘制主角的图片才行，走起~：）
</p><p>【Tile Layer Pro】
</p><p>存储主角像素块的表格称为Pattern Table，大小4KB，位于PPU $0000~$0FFF或$1000~1FFF（由PPU 控制寄存器设置，见第三天内容）。
</p><p>绘制像素块的工具可以用Tile Layer Pro，我们从一个空白的像素块开始。
</p><p>运行TLP.exe，打开MT.spr。点击View菜单，设置Format为NES。
</p><p>点击大的网格窗口的左上角第一个小方块，看到右边有个Pallete Editor窗口，这就对了，我们只能用4种颜色。现在在Tile Editor窗口中画一个小笑脸或者其他什么东东。保存文件为our.spr。很好，我们拥有了一个主角！你要是实在做不来，那就下载我做的这个。
</p><p>之后，重新下载MT.spr，重命名为our.bkg。顾名思义，这个是用于背景的。今天我们不讨论背景的制作，但为了让今天程序运行，我们必须有这个文件。
</p><p>将our.spr和our.bkg放到同一个文件夹下，你的源代码也放在这里。
</p><p>【段2变得更重要了】
</p><p>前一天，我们告诉PPU，我们将使用段2的$0000作为背景图片数据区，$1000作为主角图片数据区。这样一来段2就拥有8KB，即$2000字节。4KB就是4096B或十六进制下的$1000B。代码中我们这样实现：
</p><p>    .bank 2
</p><p>    .org $0000
</p><p>    .incbin "our.bkg"
</p><p>    .incbin "our.spr"
</p><p>.incbin包含一个二进制文件。
</p><p>【写SPR-RAM】
</p><p>SPR-RAM也称“主角信息区”，写入通过两个寄存器：$2003和$2004。类似前面载入调色板时写$2006和$2007，我们同样需要先写两次$2003，告诉PPU地址，然后将数据写入$2004。
</p><p>    lda #$00
</p><p>    sta $2003
</p><p>    sta $2003
</p><p>这样设置SPR-RAM地址为$0000。
</p><p>写$2004的内容包括4字节，具体如下：
</p><p>Y —— 屏幕上的垂直位置
</p><p>N —— 8x8 tile编号，我们包含的二进制.spr文件里面有256个不同tile，编号0~255
</p><p>C —— 一些特殊信息，我还没细看
</p><p>X —— 屏幕上的水平位置
</p><p>PPU可以放置64个主角信息。如果我们想让主角在坐标（20，50）出场，tile编号为0，C不知是啥也写0，程序如下：
</p><p>    lda #50     ; 
</p><p>    sta $2004   ; 设置纵坐标为50
</p><p>    lda #00     ; 
</p><p>    sta $2004   ; tile编号为0
</p><p>    sta $2004   ; C = 0.
</p><p>    lda #20
</p><p>    sta $2004   ; 设置横坐标为20
</p><p>咣当！主角出现（希望如此）！
</p><p>【VBlank】
</p><p>理论上我们应该在场消隐期间写入SPR-RAM。这段时间称为VBlank。只给代码，不解释。我们重点是主角。
</p><p>waitblank:
</p><p>    lda $2002  ; 
</p><p>    bpl waitblank  ; 
</p><p>不用担心，我们马上就把代码组合到一起。
</p><p>【第一个完整代码】
</p><p>新建一个our.asm文件，用记事本或其他编辑器打开，拷贝以下代码：
</p><p>    ;;--- 程序开始 ---;;
</p><p>    ; INES 文件头
</p><p>    .inesprg 1   ; 1 段代码
</p><p>    .ineschr 1   ; 1 段数据
</p><p>    .inesmir 1   ; 总是1
</p><p>    .inesmap 0   ; 使用mapper 0
</p><p>    .bank 1   ; 
</p><p>    .org $FFFA  ; 
</p><p>    .dw 0    ; dw 表示定义字，NMI中断向量 = 0（禁止）
</p><p>    .dw Start ; 复位向量，代码从Start标签处开始
</p><p>    .dw 0   ; VBlank 中断向量，0表示禁止
</p><p>    ; 
</p><p>    .bank 0   ; bank 0 - 代码段
</p><p>    .org $8000  ; 代码从 $8000开始
</p><p>Start:  ;还记得大明湖畔的复位向量吗？
</p><p>    lda #%00001000  ; 就像那天说的一样设置PPU
</p><p>    sta $2000       ; 
</p><p>    lda #%00011110  ; 
</p><p>    sta $2001       ; 
</p><p>    ldx #$00    ; 准备载入调色板
</p><p>    lda #$3F    ; 
</p><p>    sta $2006   ; 
</p><p>    lda #$00    ; 
</p><p>    sta $2006
</p><p>loadpal:                ; 
</p><p>    lda tilepal, x  ; 
</p><p>    sta $2007       ; 
</p><p>    inx             ; 
</p><p>    cpx #32         ; 
</p><p>    bne loadpal     ; 
</p><p>waitblank:         ; 等待 VBlank 
</p><p>    lda $2002  ; 读取 $2002的值
</p><p>    bpl waitblank  ; 如果bit7 == 0，那就接着waitblank
</p><p>    lda #$00   ; 写入SPR-RAM
</p><p>    sta $2003  ; 
</p><p>    lda #$00   ; 
</p><p>    sta $2003  ; 
</p><p>    lda #50  ; 
</p><p>    sta $2004 ; 
</p><p>    lda #$00  ; 
</p><p>    sta $2004 ; 
</p><p>    lda #$00 ; 
</p><p>    sta $2004 ; 
</p><p>    lda #20  ; 
</p><p>    sta $2004 ; 
</p><p>    ; 注意顺序呀！
</p><p>infin:
</p><p>    jmp infin   ; 死循环
</p><p>tilepal: .incbin "our.pal" ; 包含调色板，贴标签
</p><p>    .bank 2   ; 数据段
</p><p>    .org $0000  ; 
</p><p>    .incbin "our.bkg"  ; 空白背景数据
</p><p>    .incbin "our.spr"  ; 我们绘制的主角数据
</p><p>    ; 注意顺序呀！
</p><p>    ;;--- 代码结束 ---;;
</p><p>上面代码如果有不懂的，再看看前面几天的教程。
</p><p>【汇编】
</p><p>把所有原材料准备好（our.pal, our.bkg, our.spr, nesasm.exe, our.asm），放到同一个文件夹，打开DOS，CD到这个文件夹，输入：
</p><p>nesasm  our.asm
</p><p>命令结束后，在当前文件夹下产生our.nes文件。用模拟器运行这个nes文件试试。
</p><p>【今日回顾】
</p><p>哇，这么多！别担心，看上去很多，一旦你懂了NES，这些东西都会乖乖听你的。明天我们也许会讲背景。睡个好觉~
</p></div>
</body>
</html>
